"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleConfigFileSystemError = exports.validateConfigAccount = exports.getConfigAccountIndexById = exports.getConfigAccountByInferredIdentifier = exports.getConfigAccountByIdentifier = exports.getAccountIdentifierAndType = exports.buildConfigFromEnvironment = exports.parseConfig = exports.convertToDeprecatedConfig = exports.normalizeParsedConfig = exports.writeConfigFile = exports.formatConfigForWrite = exports.removeUndefinedFieldsFromConfigAccount = exports.readConfigFile = exports.doesConfigFileExistAtPath = exports.getConfigPathEnvironmentVariables = exports.getLocalConfigDefaultFilePath = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const config_1 = require("../constants/config");
const auth_1 = require("../constants/auth");
const FileSystemError_1 = require("../models/FileSystemError");
const environment_1 = require("../lib/environment");
const path_1 = require("../lib/path");
const files_1 = require("../constants/files");
const lang_1 = require("../utils/lang");
const HubSpotConfigError_1 = require("../models/HubSpotConfigError");
function getLocalConfigDefaultFilePath() {
    return `${(0, path_1.getCwd)()}/${config_1.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME}`;
}
exports.getLocalConfigDefaultFilePath = getLocalConfigDefaultFilePath;
function getConfigPathEnvironmentVariables() {
    const configFilePathFromEnvironment = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_CONFIG_PATH];
    const useEnvironmentConfig = process.env[config_1.ENVIRONMENT_VARIABLES.USE_ENVIRONMENT_HUBSPOT_CONFIG] ===
        'true';
    if (configFilePathFromEnvironment && useEnvironmentConfig) {
        throw new HubSpotConfigError_1.HubSpotConfigError((0, lang_1.i18n)('config.utils.getConfigPathEnvironmentVariables.invalidEnvironmentVariables'), config_1.HUBSPOT_CONFIG_ERROR_TYPES.INVALID_ENVIRONMENT_VARIABLES, config_1.HUBSPOT_CONFIG_OPERATIONS.READ);
    }
    return {
        configFilePathFromEnvironment,
        useEnvironmentConfig,
    };
}
exports.getConfigPathEnvironmentVariables = getConfigPathEnvironmentVariables;
function doesConfigFileExistAtPath(path) {
    try {
        return fs_extra_1.default.existsSync(path);
    }
    catch (error) {
        const { message, type } = handleConfigFileSystemError(error, path);
        throw new HubSpotConfigError_1.HubSpotConfigError(message, type, config_1.HUBSPOT_CONFIG_OPERATIONS.READ, { cause: error });
    }
}
exports.doesConfigFileExistAtPath = doesConfigFileExistAtPath;
function readConfigFile(configPath) {
    try {
        return fs_extra_1.default.readFileSync(configPath).toString();
    }
    catch (err) {
        const { message, type } = handleConfigFileSystemError(err, configPath);
        throw new HubSpotConfigError_1.HubSpotConfigError(message, type, config_1.HUBSPOT_CONFIG_OPERATIONS.READ, { cause: err });
    }
}
exports.readConfigFile = readConfigFile;
function removeUndefinedFieldsFromConfigAccount(account) {
    Object.keys(account).forEach(k => {
        const key = k;
        if (account[key] === undefined) {
            delete account[key];
        }
    });
    if ('auth' in account && account.auth) {
        if (account.authType === auth_1.OAUTH_AUTH_METHOD.value) {
            Object.keys(account.auth).forEach(k => {
                const key = k;
                if (account.auth?.[key] === undefined) {
                    delete account.auth?.[key];
                }
            });
        }
        if ('tokenInfo' in account.auth &&
            typeof account.auth.tokenInfo === 'object') {
            Object.keys(account.auth.tokenInfo).forEach(k => {
                const key = k;
                if (account.auth?.tokenInfo[key] === undefined) {
                    delete account.auth?.tokenInfo[key];
                }
            });
        }
    }
    return account;
}
exports.removeUndefinedFieldsFromConfigAccount = removeUndefinedFieldsFromConfigAccount;
// Ensure written config files have fields in a consistent order
function formatConfigForWrite(config) {
    const { defaultAccount, defaultCmsPublishMode, httpTimeout, allowUsageTracking, accounts, ...rest } = config;
    const orderedConfig = {
        ...(defaultAccount && { defaultAccount }),
        defaultCmsPublishMode,
        httpTimeout,
        allowUsageTracking,
        ...rest,
        accounts: accounts.map(account => {
            const { name, accountId, env, authType, ...rest } = account;
            const orderedAccount = {
                name,
                accountId,
                env,
                authType,
                ...rest,
                // using ...rest messes with the typing
            };
            return removeUndefinedFieldsFromConfigAccount(orderedAccount);
        }),
    };
    return orderedConfig;
}
exports.formatConfigForWrite = formatConfigForWrite;
function writeConfigFile(config, configPath) {
    const formattedConfig = formatConfigForWrite(config);
    const configToWrite = configPath == config_1.GLOBAL_CONFIG_PATH
        ? formattedConfig
        : convertToDeprecatedConfig(formattedConfig);
    const source = js_yaml_1.default.dump(configToWrite);
    try {
        fs_extra_1.default.ensureFileSync(configPath);
        fs_extra_1.default.writeFileSync(configPath, source);
    }
    catch (err) {
        throw new FileSystemError_1.FileSystemError({ cause: err }, {
            filepath: configPath,
            operation: 'write',
        });
    }
}
exports.writeConfigFile = writeConfigFile;
function getAccountType(sandboxAccountType) {
    if (sandboxAccountType) {
        if (sandboxAccountType.toUpperCase() === 'DEVELOPER') {
            return config_1.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX;
        }
        if (sandboxAccountType.toUpperCase() === 'STANDARD') {
            return config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX;
        }
    }
    return config_1.HUBSPOT_ACCOUNT_TYPES.STANDARD;
}
function normalizeParsedConfig(parsedConfig) {
    if (!parsedConfig.portals && !parsedConfig.accounts) {
        parsedConfig.accounts = [];
    }
    if (parsedConfig.portals) {
        parsedConfig.accounts = parsedConfig.portals.map(account => {
            if (account.portalId) {
                account.accountId = account.portalId;
                delete account.portalId;
            }
            if (!account.accountType) {
                account.accountType = getAccountType(account.sandboxAccountType);
                delete account.sandboxAccountType;
            }
            return account;
        });
        delete parsedConfig.portals;
    }
    if (parsedConfig.defaultPortal) {
        const defaultAccount = getConfigAccountByInferredIdentifier(parsedConfig.accounts, parsedConfig.defaultPortal);
        if (defaultAccount) {
            parsedConfig.defaultAccount = defaultAccount.accountId;
        }
        delete parsedConfig.defaultPortal;
    }
    if (parsedConfig.defaultMode) {
        parsedConfig.defaultCmsPublishMode = parsedConfig.defaultMode;
        delete parsedConfig.defaultMode;
    }
    return parsedConfig;
}
exports.normalizeParsedConfig = normalizeParsedConfig;
function convertToDeprecatedConfig(config) {
    const deprecatedConfig = structuredClone(config);
    if (config.defaultAccount) {
        const defaultAccount = getConfigAccountByIdentifier(config.accounts, config_1.ACCOUNT_IDENTIFIERS.ACCOUNT_ID, config.defaultAccount);
        if (defaultAccount) {
            deprecatedConfig.defaultPortal = defaultAccount.name;
            delete deprecatedConfig.defaultAccount;
        }
    }
    const portals = config.accounts.map(account => {
        if (account.accountId) {
            const deprecatedAccount = structuredClone(account);
            deprecatedAccount.portalId = account.accountId;
            // @ts-expect-error deleting accountId is intential since using deprecated config format
            delete deprecatedAccount.accountId;
            return deprecatedAccount;
        }
        return account;
    });
    deprecatedConfig.portals = portals;
    delete deprecatedConfig.accounts;
    return deprecatedConfig;
}
exports.convertToDeprecatedConfig = convertToDeprecatedConfig;
function parseConfig(configSource, configPath) {
    let parsedYaml;
    try {
        parsedYaml = js_yaml_1.default.load(configSource);
    }
    catch (err) {
        throw new HubSpotConfigError_1.HubSpotConfigError((0, lang_1.i18n)('config.utils.parseConfig.error', { configPath: configPath }), config_1.HUBSPOT_CONFIG_ERROR_TYPES.YAML_PARSING, config_1.HUBSPOT_CONFIG_OPERATIONS.READ, { cause: err });
    }
    return normalizeParsedConfig(parsedYaml);
}
exports.parseConfig = parseConfig;
function buildConfigFromEnvironment() {
    const apiKey = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_API_KEY];
    const clientId = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_CLIENT_ID];
    const clientSecret = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_CLIENT_SECRET];
    const personalAccessKey = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_PERSONAL_ACCESS_KEY];
    const accountIdVar = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_ACCOUNT_ID] ||
        process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_PORTAL_ID];
    const refreshToken = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_REFRESH_TOKEN];
    const hubspotEnvironment = process.env[config_1.ENVIRONMENT_VARIABLES.HUBSPOT_ENVIRONMENT];
    const httpTimeoutVar = process.env[config_1.ENVIRONMENT_VARIABLES.HTTP_TIMEOUT];
    const httpUseLocalhostVar = process.env[config_1.ENVIRONMENT_VARIABLES.HTTP_USE_LOCALHOST];
    const allowUsageTrackingVar = process.env[config_1.ENVIRONMENT_VARIABLES.ALLOW_USAGE_TRACKING];
    const defaultCmsPublishModeVar = process.env[config_1.ENVIRONMENT_VARIABLES.DEFAULT_CMS_PUBLISH_MODE];
    if (!accountIdVar) {
        throw new HubSpotConfigError_1.HubSpotConfigError((0, lang_1.i18n)('config.utils.buildConfigFromEnvironment.missingAccountId'), config_1.HUBSPOT_CONFIG_ERROR_TYPES.INVALID_ENVIRONMENT_VARIABLES, config_1.HUBSPOT_CONFIG_OPERATIONS.READ);
    }
    const accountId = parseInt(accountIdVar);
    const httpTimeout = httpTimeoutVar ? parseInt(httpTimeoutVar) : undefined;
    const httpUseLocalhost = httpUseLocalhostVar
        ? httpUseLocalhostVar === 'true'
        : undefined;
    const allowUsageTracking = allowUsageTrackingVar
        ? allowUsageTrackingVar === 'true'
        : undefined;
    const defaultCmsPublishMode = defaultCmsPublishModeVar === files_1.CMS_PUBLISH_MODE.draft ||
        defaultCmsPublishModeVar === files_1.CMS_PUBLISH_MODE.publish
        ? defaultCmsPublishModeVar
        : undefined;
    const env = (0, environment_1.getValidEnv)(hubspotEnvironment);
    let account;
    if (personalAccessKey) {
        account = {
            authType: auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
            accountId,
            personalAccessKey,
            env,
            name: accountIdVar,
            auth: {
                tokenInfo: {},
            },
        };
    }
    else if (clientId && clientSecret && refreshToken) {
        account = {
            authType: auth_1.OAUTH_AUTH_METHOD.value,
            accountId,
            auth: {
                clientId,
                clientSecret,
                scopes: auth_1.OAUTH_SCOPES.map((scope) => scope.value),
                tokenInfo: {
                    refreshToken,
                },
            },
            env,
            name: accountIdVar,
        };
    }
    else if (apiKey) {
        account = {
            authType: auth_1.API_KEY_AUTH_METHOD.value,
            accountId,
            apiKey,
            env,
            name: accountIdVar,
        };
    }
    else {
        throw new HubSpotConfigError_1.HubSpotConfigError((0, lang_1.i18n)('config.utils.buildConfigFromEnvironment.invalidAuthType'), config_1.HUBSPOT_CONFIG_ERROR_TYPES.INVALID_ENVIRONMENT_VARIABLES, config_1.HUBSPOT_CONFIG_OPERATIONS.READ);
    }
    return {
        accounts: [account],
        defaultAccount: accountId,
        httpTimeout,
        httpUseLocalhost,
        allowUsageTracking,
        defaultCmsPublishMode,
    };
}
exports.buildConfigFromEnvironment = buildConfigFromEnvironment;
function getAccountIdentifierAndType(accountIdentifier) {
    const identifierAsNumber = typeof accountIdentifier === 'number'
        ? accountIdentifier
        : parseInt(accountIdentifier);
    const isId = !isNaN(identifierAsNumber);
    return {
        identifier: isId ? identifierAsNumber : accountIdentifier,
        identifierType: isId
            ? config_1.ACCOUNT_IDENTIFIERS.ACCOUNT_ID
            : config_1.ACCOUNT_IDENTIFIERS.NAME,
    };
}
exports.getAccountIdentifierAndType = getAccountIdentifierAndType;
function getConfigAccountByIdentifier(accounts, identifierFieldName, identifier) {
    return accounts.find(account => account[identifierFieldName] === identifier);
}
exports.getConfigAccountByIdentifier = getConfigAccountByIdentifier;
function getConfigAccountByInferredIdentifier(accounts, accountIdentifier) {
    const { identifier, identifierType } = getAccountIdentifierAndType(accountIdentifier);
    const account = getConfigAccountByIdentifier(accounts, identifierType, identifier);
    if (account) {
        return account;
    }
    // Fallback to handle accounts with numbers as names
    return getConfigAccountByIdentifier(accounts, config_1.ACCOUNT_IDENTIFIERS.NAME, String(accountIdentifier));
}
exports.getConfigAccountByInferredIdentifier = getConfigAccountByInferredIdentifier;
function getConfigAccountIndexById(accounts, id) {
    return accounts.findIndex(account => account.accountId === id);
}
exports.getConfigAccountIndexById = getConfigAccountIndexById;
function validateConfigAccount(account) {
    const validationErrors = [];
    if (!account || typeof account !== 'object') {
        validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingAccount'));
        return { isValid: false, errors: validationErrors };
    }
    if (!account.accountId) {
        validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingAccountId'));
        return { isValid: false, errors: validationErrors };
    }
    if (!account.authType) {
        validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingAuthType', {
            accountId: account.accountId,
        }));
        return { isValid: false, errors: validationErrors };
    }
    if (account.authType === auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value) {
        const isValidPersonalAccessKeyAccount = 'personalAccessKey' in account && Boolean(account.personalAccessKey);
        if (!isValidPersonalAccessKeyAccount) {
            validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingPersonalAccessKey', {
                accountId: account.accountId,
            }));
        }
    }
    if (account.authType === auth_1.OAUTH_AUTH_METHOD.value) {
        const isValidOAuthAccount = 'auth' in account && Boolean(account.auth);
        if (!isValidOAuthAccount) {
            validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingAuth', {
                accountId: account.accountId,
            }));
        }
    }
    if (account.authType === auth_1.API_KEY_AUTH_METHOD.value) {
        const isValidAPIKeyAccount = 'apiKey' in account && Boolean(account.apiKey);
        if (!isValidAPIKeyAccount) {
            validationErrors.push((0, lang_1.i18n)('config.utils.validateConfigAccount.missingApiKey', {
                accountId: account.accountId,
            }));
        }
    }
    return { isValid: validationErrors.length === 0, errors: validationErrors };
}
exports.validateConfigAccount = validateConfigAccount;
function handleConfigFileSystemError(error, path) {
    let message;
    let type = config_1.HUBSPOT_CONFIG_ERROR_TYPES.UNKNOWN;
    if (error instanceof Error && 'code' in error) {
        if (error.code === 'ENOENT') {
            message = (0, lang_1.i18n)('config.utils.handleConfigFileSystemError.configNotFoundError', { path });
            type = config_1.HUBSPOT_CONFIG_ERROR_TYPES.CONFIG_NOT_FOUND;
        }
        else if (error.code === 'EACCES') {
            message = (0, lang_1.i18n)('config.utils.handleConfigFileSystemError.insufficientPermissionsError', { path });
            type = config_1.HUBSPOT_CONFIG_ERROR_TYPES.INSUFFICIENT_PERMISSIONS;
        }
    }
    return { message, type };
}
exports.handleConfigFileSystemError = handleConfigFileSystemError;
